﻿#region Copyright(C) 2009 Xiong Wei All rights reserved.
// ==============================================================================
// Copyright(C) 2009 Xiong Wei
//
// SYSTEM NAME          : 
// COMPONENT ID         : LinqTest.DBHelper
// COMPONENT DESC       : 
//
// CREATED DATE/BY     : 2009 / Xiong Wei
//
// REVISION HISTORY     :
// DATE/BY ISSUE#/SR#/CS/PM#/OTHERS    DESCRIPTION OF CHANGE
// 
// 
// ==============================================================================

#endregion

using System;
using System.Data.Linq;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;

namespace Portal
{
    public static class LinqHelper
    {

        public static IQueryable<T> Sorting<T>(this IQueryable<T> source, string sortExpression, string sortDirection)
        {
            return DataSorting<T>(source, sortExpression, sortDirection);

        }

        public static IQueryable<T> Sorting<T>(this IQueryable<T> source, string sortExpression, bool sortDirection)
        {
            return DataSorting<T>(source, sortExpression, sortDirection);
        }

        public static IQueryable<T> DataSorting<T>(IQueryable<T> source, string sortExpression, string sortDirection)
        {

            var sortingDir = string.Empty;
            switch (sortDirection.ToUpper().Trim())
            {
                case "ASC":
                    sortingDir = "OrderBy";
                    break;
                case "DESC":
                    sortingDir = "OrderByDescending";
                    break;
            }

            ParameterExpression param = Expression.Parameter(typeof(T), "c");
            Expression expr = GetPropertyLambdaExpression(source, sortExpression, param, sortingDir);
            if (expr != null)
            {
                IQueryable<T> query = source.AsQueryable().Provider.CreateQuery<T>(expr);
                return query;
            }

            return source;
        }

        private static Expression GetPropertyLambdaExpression<T>(IQueryable<T> source, string field, ParameterExpression param, string sortingDir)
        {
            //获取每级属性如c.Users.Proiles.UserId
            var props = field.Split('.');
            Expression propertyAccess = param;
            var typeOfProp = typeof(T);
            Type typee = typeOfProp;
            int i = 0;
            do
            {
                PropertyInfo property = typeOfProp.GetProperty(props[i]);
                if (property == null)
                {
                    foreach (var type in typeOfProp.GetInterfaces())
                    {
                        property = type.GetProperty(props[i]);
                        if (property != null)
                        {
                            typee = type;
                            break;
                        }
                    }
                    if (property == null) return null;
                }
                typeOfProp = property.PropertyType;
                propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
                i++;
            } while (i < props.Length);

            var types = new Type[2];
            types[0] = typeof(T);
            types[1] = typeOfProp;
            return Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(propertyAccess, param));

        }


        /// <summary>
        /// 数据自定义排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">源</param>
        /// <param name="sortExpression">排序的列</param>
        /// <param name="sortDirection">排序方向</param>
        /// <returns></returns>
        public static IQueryable<T> DataSorting<T>(IQueryable<T> source, string sortExpression, bool sortDirection)
        {
            //正序还是反序
            var sortingDir = sortDirection ? "OrderBy" : "OrderByDescending";
            ParameterExpression param = Expression.Parameter(typeof(T), "c");
            Expression expr = GetPropertyLambdaExpression(source, sortExpression, param, sortingDir);
            if (expr != null)
            {
                IQueryable<T> query = source.AsQueryable().Provider.CreateQuery<T>(expr);
                return query;
            }
            return source;

        }

        public static IQueryable<T> DataPaging<T>(IQueryable<T> source, int pageNumber, int pageSize)
        {
            return source.Skip(pageNumber * pageSize).Take(pageSize);
        }

        public static IQueryable<T> SortingAndPaging<T>(IQueryable<T> source, string sortExpression, string sortDirection, int pageNumber, int pageSize)
        {
            IQueryable<T> query = DataSorting<T>(source, sortExpression, sortDirection);
            return DataPaging(query, pageNumber, pageSize);
        }

        /// <summary>
        /// 辅助LinqToSql实体与原DataContext分离
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        public static void Detatch<TEntity>(TEntity entity) where TEntity : class
        {

            var type = entity.GetType();

            PropertyInfo[] properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

            foreach (var property in properties)
            {

                string name = property.Name;

                if (property.PropertyType.IsGenericType &&

                property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<TEntity>))
                {

                    property.SetValue(entity, null, null);

                }

            }

            FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            foreach (var coName in fields)
            {

                string name = coName.Name;

                if (coName.FieldType.IsGenericType &&

                coName.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<TEntity>))
                {

                    coName.SetValue(entity, null);

                }

            }

            EventInfo eventPropertyChanged = type.GetEvent("PropertyChanged");

            EventInfo eventPropertyChanging = type.GetEvent("PropertyChanging");

            if (eventPropertyChanged != null)
            {

                eventPropertyChanged.RemoveEventHandler(entity, null);

            }

            if (eventPropertyChanging != null)
            {

                eventPropertyChanging.RemoveEventHandler(entity, null);

            }

        }
    }
}